summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/common/wall_clock.cpp8
-rw-r--r--src/common/wall_clock.h20
-rw-r--r--src/common/x64/native_clock.cpp7
-rw-r--r--src/common/x64/native_clock.h3
-rw-r--r--src/core/core_timing.cpp7
-rw-r--r--src/core/core_timing.h3
-rw-r--r--src/video_core/gpu.cpp11
7 files changed, 47 insertions, 12 deletions
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp
index ad8db06b0..dc0dcbd68 100644
--- a/src/common/wall_clock.cpp
+++ b/src/common/wall_clock.cpp
@@ -32,6 +32,10 @@ public:
return GetHostTicksElapsed() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den;
}
+ u64 GetGPUTick() const override {
+ return GetHostTicksElapsed() * NsToGPUTickRatio::num / NsToGPUTickRatio::den;
+ }
+
u64 GetHostTicksNow() const override {
return static_cast<u64>(SteadyClock::Now().time_since_epoch().count());
}
@@ -52,12 +56,12 @@ std::unique_ptr<WallClock> CreateOptimalClock() {
#ifdef ARCHITECTURE_x86_64
const auto& caps = GetCPUCaps();
- if (caps.invariant_tsc && caps.tsc_frequency >= WallClock::CNTFRQ) {
+ if (caps.invariant_tsc && caps.tsc_frequency >= WallClock::GPUTickFreq) {
return std::make_unique<X64::NativeClock>(caps.tsc_frequency);
} else {
// Fallback to StandardWallClock if the hardware TSC
// - Is not invariant
- // - Is not more precise than CNTFRQ
+ // - Is not more precise than GPUTickFreq
return std::make_unique<StandardWallClock>();
}
#else
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h
index 56c18ca25..fcfdd637c 100644
--- a/src/common/wall_clock.h
+++ b/src/common/wall_clock.h
@@ -13,7 +13,8 @@ namespace Common {
class WallClock {
public:
- static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz
+ static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz
+ static constexpr u64 GPUTickFreq = 614'400'000; // GM20B GPU Tick Frequency = 614.4 MHz
virtual ~WallClock() = default;
@@ -29,6 +30,9 @@ public:
/// @returns The guest CNTPCT ticks since the construction of this clock.
virtual u64 GetCNTPCT() const = 0;
+ /// @returns The guest GPU ticks since the construction of this clock.
+ virtual u64 GetGPUTick() const = 0;
+
/// @returns The raw host timer ticks since an indeterminate epoch.
virtual u64 GetHostTicksNow() const = 0;
@@ -46,6 +50,10 @@ public:
return us * UsToCNTPCTRatio::num / UsToCNTPCTRatio::den;
}
+ static inline u64 NSToGPUTick(u64 ns) {
+ return ns * NsToGPUTickRatio::num / NsToGPUTickRatio::den;
+ }
+
static inline u64 CNTPCTToNS(u64 cntpct) {
return cntpct * NsToCNTPCTRatio::den / NsToCNTPCTRatio::num;
}
@@ -54,6 +62,14 @@ public:
return cntpct * UsToCNTPCTRatio::den / UsToCNTPCTRatio::num;
}
+ static inline u64 GPUTickToNS(u64 gpu_tick) {
+ return gpu_tick * NsToGPUTickRatio::den / NsToGPUTickRatio::num;
+ }
+
+ static inline u64 CNTPCTToGPUTick(u64 cntpct) {
+ return cntpct * CNTPCTToGPUTickRatio::num / CNTPCTToGPUTickRatio::den;
+ }
+
protected:
using NsRatio = std::nano;
using UsRatio = std::micro;
@@ -63,6 +79,8 @@ protected:
using NsToMsRatio = std::ratio_divide<std::nano, std::milli>;
using NsToCNTPCTRatio = std::ratio<CNTFRQ, std::nano::den>;
using UsToCNTPCTRatio = std::ratio<CNTFRQ, std::micro::den>;
+ using NsToGPUTickRatio = std::ratio<GPUTickFreq, std::nano::den>;
+ using CNTPCTToGPUTickRatio = std::ratio<GPUTickFreq, CNTFRQ>;
};
std::unique_ptr<WallClock> CreateOptimalClock();
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp
index 5d1eb0590..7d2a26bd9 100644
--- a/src/common/x64/native_clock.cpp
+++ b/src/common/x64/native_clock.cpp
@@ -12,7 +12,8 @@ NativeClock::NativeClock(u64 rdtsc_frequency_)
ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency)},
us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency)},
ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency)},
- cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)} {}
+ cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)},
+ gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency)} {}
std::chrono::nanoseconds NativeClock::GetTimeNS() const {
return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_rdtsc_factor)};
@@ -30,6 +31,10 @@ u64 NativeClock::GetCNTPCT() const {
return MultiplyHigh(GetHostTicksElapsed(), cntpct_rdtsc_factor);
}
+u64 NativeClock::GetGPUTick() const {
+ return MultiplyHigh(GetHostTicksElapsed(), gputick_rdtsc_factor);
+}
+
u64 NativeClock::GetHostTicksNow() const {
return FencedRDTSC();
}
diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h
index d6f8626c1..334415eff 100644
--- a/src/common/x64/native_clock.h
+++ b/src/common/x64/native_clock.h
@@ -19,6 +19,8 @@ public:
u64 GetCNTPCT() const override;
+ u64 GetGPUTick() const override;
+
u64 GetHostTicksNow() const override;
u64 GetHostTicksElapsed() const override;
@@ -33,6 +35,7 @@ private:
u64 us_rdtsc_factor;
u64 ms_rdtsc_factor;
u64 cntpct_rdtsc_factor;
+ u64 gputick_rdtsc_factor;
};
} // namespace Common::X64
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 9a1d5a69a..e57bca70a 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -197,6 +197,13 @@ u64 CoreTiming::GetClockTicks() const {
return ticks;
}
+u64 CoreTiming::GetGPUTicks() const {
+ if (is_multicore) [[likely]] {
+ return clock->GetGPUTick();
+ }
+ return Common::WallClock::CNTPCTToGPUTick(ticks);
+}
+
std::optional<s64> CoreTiming::Advance() {
std::scoped_lock lock{advance_lock, basic_lock};
global_timer = GetGlobalTimeNs().count();
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index fdacdd94a..1873852c4 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -119,6 +119,9 @@ public:
/// Returns the current CNTPCT tick value.
u64 GetClockTicks() const;
+ /// Returns the current GPU tick value.
+ u64 GetGPUTicks() const;
+
/// Returns current time in microseconds.
std::chrono::microseconds GetGlobalTimeUs() const;
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 70762c51a..db385076d 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -193,18 +193,13 @@ struct GPU::Impl {
}
[[nodiscard]] u64 GetTicks() const {
- // This values were reversed engineered by fincs from NVN
- // The GPU clock is 614.4 MHz
- using NsToGPUTickRatio = std::ratio<614'400'000, std::nano::den>;
- static_assert(NsToGPUTickRatio::num == 384 && NsToGPUTickRatio::den == 625);
-
- u64 nanoseconds = system.CoreTiming().GetGlobalTimeNs().count();
+ u64 gpu_tick = system.CoreTiming().GetGPUTicks();
if (Settings::values.use_fast_gpu_time.GetValue()) {
- nanoseconds /= 256;
+ gpu_tick /= 256;
}
- return nanoseconds * NsToGPUTickRatio::num / NsToGPUTickRatio::den;
+ return gpu_tick;
}
[[nodiscard]] bool IsAsync() const {